home *** CD-ROM | disk | FTP | other *** search
- /*
- * (c) Copyright 1992 by Panagiotis Tsirigotis
- * All rights reserved. The file named COPYRIGHT specifies the terms
- * and conditions for redistribution.
- */
-
- static char RCSid[] = "$Id: conf.c,v 5.3 1993/01/14 01:57:56 panos Exp $" ;
-
- #include <sys/types.h>
- #include <netinet/in.h>
- #include <syslog.h>
- #include <fcntl.h>
- #include <string.h>
- #include <netdb.h>
-
- #include "pset.h"
- #include "misc.h"
- #include "xlog.h"
-
- #include "attr.h"
- #include "defs.h"
- #include "service.h"
- #include "conf.h"
- #include "state.h"
- #include "config.h"
- #include "logoptions.h"
-
- char *malloc() ;
- void endservent() ;
- void endprotoent() ;
- void endrpcent() ;
-
- void msg() ;
- void out_of_memory() ;
-
- PRIVATE status_e conf_setup() ;
- PRIVATE status_e fix_server_argv() ;
- PRIVATE status_e attr_fill() ;
- PRIVATE void remove_disabled_services() ;
- PRIVATE status_e attr_check() ;
- PRIVATE status_e check_entry() ;
- PRIVATE void dump_configuration() ;
-
- /*
- * Pset iterator used by functions in this file.
- * It lives only when get_configuration is called (i.e. it is created and
- * destroyed each time). This is because the pset it is iterating on
- * changes.
- */
- static psi_h iter ;
-
-
- #define CHECK_AND_CLEAR( scp, mask, mask_name ) \
- if ( M_IS_SET( mask, LO_USERID ) ) \
- { \
- msg( LOG_WARNING, func, \
- "%s service: clearing USERID option from %s", scp->id, mask_name ) ; \
- M_CLEAR( mask, LO_USERID ) ; \
- }
-
-
- status_e get_configuration( confp )
- struct configuration *confp ;
- {
- int config_fd ;
- struct service *sp ;
- void parse_conf_file() ;
- char *func = "get_configuration" ;
-
- if ( conf_setup( &config_fd, confp, &iter ) == FAILED )
- return( FAILED ) ;
-
- parse_conf_file( config_fd, confp ) ;
- Sclose( config_fd ) ;
-
- remove_disabled_services( confp ) ;
-
- for ( sp = SP( psi_start( iter ) ) ; sp ; sp = SP( psi_next( iter ) ) )
- {
- struct service_config *scp = CONF( sp ) ;
-
- if ( check_entry( sp ) == FAILED )
- {
- svc_free( sp ) ;
- psi_remove( iter ) ;
- continue ;
- }
- if ( attr_fill( scp, CONF( confp->defaults ) ) == FAILED )
- {
- svc_free( sp ) ;
- psi_remove( iter ) ;
- continue ;
- }
-
- /*
- * If the INTERCEPT flag is set, change this service to an internal
- * service using the special INTERCEPT builtin.
- */
- if ( IS_INTERCEPTED( scp ) )
- {
- sp->builtin = find_special_builtin( INTERCEPT_SERVICE_NAME,
- scp->socket_type ) ;
- if ( sp->builtin == NULL )
- {
- msg( LOG_ERR, func, "removing service %s", scp->id ) ;
- svc_free( sp ) ;
- psi_remove( iter ) ;
- continue ;
- }
- M_SET( scp->type, ST_INTERNAL ) ;
- }
-
- /*
- * Clear the USERID flag for the identity service because
- * it may lead to loops (for example, remote xinetd issues request,
- * local xinetd issues request to remote xinetd etc.)
- * We identify the identity service by its (protocol,port) combination.
- */
- if ( scp->port == IDENTITY_SERVICE_PORT &&
- scp->protocol.value == IPPROTO_TCP )
- {
- CHECK_AND_CLEAR( scp, scp->log_on_success, "log_on_success" ) ;
- CHECK_AND_CLEAR( scp, scp->log_on_failure, "log_on_failure" ) ;
- }
- }
-
- psi_destroy( iter ) ;
-
- if ( debug.on )
- {
- int fd = -1 ;
-
- xlog_control( ps.rws.program_log, XLOG_GETFD, &fd ) ;
- if ( fd != -1 )
- dump_configuration( confp, fd ) ;
- }
-
- endservent() ;
- endprotoent() ;
- #ifndef NO_RPC
- endrpcent() ;
- #endif
- return( OK ) ;
- }
-
-
- void free_configuration( confp )
- struct configuration *confp ;
- {
- register unsigned u ;
-
- for ( u = 0 ; u < pset_count( confp->services ) ; u++ )
- {
- struct service *sp = SP( pset_pointer( confp->services, u ) ) ;
-
- if ( sp->ref_count == 0 )
- svc_free( sp ) ;
- }
- pset_destroy( confp->services ) ;
- if ( confp->defaults->ref_count == 0 )
- svc_free( confp->defaults ) ;
- }
-
-
- void dump_current_configuration( fd )
- int fd ;
- {
- struct configuration current ;
- void dump_configuration() ;
-
- current.services = SERVICES( ps ) ;
- current.defaults = ps.rws.cs.defaults ;
- dump_configuration( ¤t, fd ) ;
- }
-
-
- PRIVATE void dump_configuration( confp, fd )
- struct configuration *confp ;
- int fd ;
- {
- void list_services() ;
- void tabprint() ;
-
- sconf_dump( CONF( confp->defaults ), fd, 0, TRUE ) ;
- tabprint( fd, 0, "\n" ) ;
- list_services( confp->services, fd ) ;
- }
-
-
-
- PRIVATE status_e conf_setup( fdp, confp, iterp )
- int *fdp ;
- struct configuration *confp ;
- psi_h *iterp ;
- {
- int fd ;
- pset_h pset ;
- psi_h pset_iter ;
- struct service *sp ;
- char *func = "conf_setup" ;
-
- /*
- * Open configuration file
- */
- fd = open( ps.ros.config_file, O_RDONLY ) ;
-
- if ( fd == -1 )
- {
- msg( LOG_CRIT, func, "open( %s ) failed: %m", ps.ros.config_file ) ;
- return( FAILED ) ;
- }
-
- if ( ( pset = pset_create( 0, 0 ) ) == NULL )
- {
- msg( LOG_CRIT, func, "can't create service table" ) ;
- (void) close( fd ) ;
- return( FAILED ) ;
- }
-
- if ( ( sp = svc_new( (struct service_config *)NULL ) ) == NULL )
- {
- msg( LOG_CRIT, func, "can't allocate defaults service" ) ;
- pset_destroy( pset ) ;
- (void) close( fd ) ;
- return( FAILED ) ;
- }
-
- if ( ( pset_iter = psi_create( pset ) ) == NULL )
- {
- msg( LOG_CRIT, func, "can't create service table iterator" ) ;
- svc_free( sp ) ;
- pset_destroy( pset ) ;
- (void) close( fd ) ;
- return( FAILED ) ;
- }
-
- *fdp = fd ;
- confp->services = pset ;
- confp->defaults = sp ;
- *iterp = pset_iter ;
- return( OK ) ;
- }
-
-
- PRIVATE status_e fix_server_argv( scp )
- struct service_config *scp ;
- {
- char *server_name ;
- char *func = "fix_server_argv" ;
-
- /*
- * Check if the user specified any server arguments.
- * If not, then the server_argv has not been allocated yet,
- * so malloc it (size 2)
- * Put in argv[ 0 ] the last component of the server pathname
- */
- if ( ! SPECIFIED( scp, A_SERVER_ARGS ) )
- {
- scp->server_argv = (char **) malloc( 2 * sizeof( char * ) ) ;
- if ( scp->server_argv == NULL )
- {
- out_of_memory( func ) ;
- return( FAILED ) ;
- }
- scp->server_argv[ 1 ] = NULL ;
- PRESENT( scp, A_SERVER_ARGS ) ;
- }
-
- /*
- * Determine server name
- */
- server_name = strrchr( scp->server, '/' ) ;
- if ( server_name == NULL )
- server_name = scp->server ;
- else
- server_name++ ; /* skip the '/' */
-
- /*
- * Place it in argv[ 0 ]
- */
- scp->server_argv[ 0 ] = make_string( 1, server_name ) ;
- if ( scp->server_argv[ 0 ] == NULL )
- {
- out_of_memory( func ) ;
- return( FAILED ) ;
- }
- return( OK ) ;
- }
-
-
-
- #define USE_DEFAULT( scp, def, attr_id ) \
- ( ! SPECIFIED( scp, attr_id ) && SPECIFIED( def, attr_id ) )
-
- PRIVATE status_e attr_fill( scp, def )
- struct service_config *scp ;
- struct service_config *def ;
- {
- char *func = "attr_fill" ;
- status_e setup_environ() ;
-
- if ( ! IS_INTERNAL( scp ) && fix_server_argv( scp ) == FAILED )
- return( FAILED ) ;
-
- if ( ! SPECIFIED( scp, A_INSTANCES ) )
- {
- scp->instances = SPECIFIED( def, A_INSTANCES ) ? def->instances
- : DEFAULT_INSTANCE_LIMIT ;
- PRESENT( scp, A_INSTANCES ) ;
- }
-
- if ( USE_DEFAULT( scp, def, A_LOG_ON_SUCCESS ) )
- {
- scp->log_on_success = def->log_on_success ;
- PRESENT( scp, A_LOG_ON_SUCCESS ) ;
- }
-
- if ( USE_DEFAULT( scp, def, A_LOG_ON_FAILURE ) )
- {
- scp->log_on_failure = def->log_on_failure ;
- PRESENT( scp, A_LOG_ON_FAILURE ) ;
- }
-
- if ( USE_DEFAULT( scp, def, A_LOG_TYPE ) )
- {
- switch ( LOG( def )->log_type )
- {
- case L_NONE:
- LOG( scp )->log_type = L_NONE ;
- break ;
-
- case L_SYSLOG:
- LOG( scp )->log_type = L_SYSLOG ;
- SYSLOG( LOG( scp ) )->facility = SYSLOG( LOG( def ) )->facility ;
- SYSLOG( LOG( scp ) )->level = SYSLOG( LOG( def ) )->level ;
- break ;
-
- case L_FILE:
- LOG( scp )->log_type = L_COMMON_FILE ;
- break ;
-
- default:
- msg( LOG_ERR, func,
- "bad log type: %d", (int) LOG( def )->log_type ) ;
- return( FAILED ) ;
- }
- PRESENT( scp, A_LOG_TYPE ) ;
- }
- if ( setup_environ( scp, def ) == FAILED )
- return( FAILED ) ;
- return( OK ) ;
- }
-
-
- PRIVATE void remove_disabled_services( confp )
- struct configuration *confp ;
- {
- pset_h disabled_services ;
- register struct service *sp ;
- struct service_config *defaults = CONF( confp->defaults ) ;
-
- if ( ! SPECIFIED( defaults, A_DISABLED ) )
- return ;
-
- disabled_services = defaults->disabled ;
-
- for ( sp = SP( psi_start( iter ) ) ; sp ; sp = SP( psi_next( iter ) ) )
- {
- register char *sid = CONF( sp )->id ;
- register unsigned u ;
-
- for ( u = 0 ; u < pset_count( disabled_services ) ; u++ )
- if ( EQ( sid, (char *) pset_pointer( disabled_services, u ) ) )
- {
- svc_free( sp ) ;
- psi_remove( iter ) ;
- break ;
- }
- }
- }
-
-
- /*
- * Check if all required attributes have been specified
- */
- PRIVATE status_e attr_check( scp )
- register struct service_config *scp ;
- {
- mask_t necessary_and_specified ;
- mask_t necessary_and_missing ;
- mask_t must_specify = NECESSARY_ATTRIBUTES ;
- register int attr_id ;
- char *attr_name ;
- char *func = "attr_check" ;
- char *attr_name_lookup() ;
-
- /*
- * Determine what attributes must be specified
- */
- if ( ! IS_INTERNAL( scp ) )
- M_OR( must_specify, must_specify, NECESSARY_ATTRIBUTES_EXTERNAL ) ;
-
- if ( IS_RPC( scp ) )
- M_OR( must_specify, must_specify, NECESSARY_ATTRIBUTES_RPC ) ;
-
- if ( IS_UNLISTED( scp ) )
- M_OR( must_specify, must_specify, NECESSARY_ATTRIBUTES_UNLISTED ) ;
- else
- M_OR( must_specify, must_specify, NECESSARY_ATTRIBUTES_LISTED ) ;
-
- /*
- * Check if all necessary attributes have been specified
- *
- * NOTE: None of the necessary attributes can belong to "defaults"
- * This is why we use the attributes_specified mask.
- */
- M_AND( necessary_and_specified, scp->specified_attributes, must_specify ) ;
- M_XOR( necessary_and_missing, necessary_and_specified, must_specify ) ;
-
- if ( M_ARE_ALL_CLEAR( necessary_and_missing ) )
- return( OK ) ;
-
- for ( attr_id = 0 ; attr_id < SERVICE_ATTRIBUTES ; attr_id++ )
- if ( M_IS_SET( necessary_and_missing, attr_id ) &&
- ( attr_name = attr_name_lookup( attr_id ) ) != NULL )
- msg( LOG_ERR, func,
- "Service %s missing attribute %s", scp->id, attr_name ) ;
- return( FAILED ) ;
- }
-
-
- /*
- * Perform validity checks on the specified entry
- *
- * Also does the following:
- * 1. If this is an internal service, it finds the function that
- * implements it
- * 2. For RPC services, it finds the program number
- * 3. For non-RPC services, it finds the port number.
- */
- PRIVATE status_e check_entry( sp )
- register struct service *sp ;
- {
- register struct service_config *scp = CONF( sp ) ;
- char *func = "check_entry" ;
-
- if ( attr_check( scp ) == FAILED )
- return( FAILED ) ;
-
- /*
- * Currently, we cannot intercept:
- * 1) internal services
- * 2) multi-threaded services
- * We clear the INTERCEPT flag without disabling the service.
- */
- if ( IS_INTERCEPTED( scp ) )
- {
- if ( IS_INTERNAL( scp ) )
- {
- msg( LOG_ERR, func,
- "Internal services cannot be intercepted: %s ", scp->id ) ;
- M_CLEAR( scp->flags, SF_INTERCEPT ) ;
- }
- if ( scp->wait == NO )
- {
- msg( LOG_ERR, func,
- "Multi-threaded services cannot be intercepted: %s", scp->id ) ;
- M_CLEAR( scp->flags, SF_INTERCEPT ) ;
- }
- }
-
- if ( IS_UNLISTED( scp ) )
- {
- /*
- * XXX: We don't support unlisted RPC services
- */
- if ( IS_RPC( scp ) )
- {
- msg( LOG_ERR, func,
- "%s: unlisted RPC services not supported", scp->id ) ;
- return( FAILED ) ;
- }
- return( OK ) ;
- }
-
- if ( IS_INTERNAL( scp ) &&
- ( sp->builtin = find_builtin( scp->name, scp->socket_type ) ) == NULL )
- return( FAILED ) ;
-
- #ifndef NO_RPC
- if ( IS_RPC( scp ) )
- {
- struct rpcent *rep = getrpcbyname( scp->name ) ;
-
- if ( rep == NULL )
- {
- msg( LOG_ERR, func, "unknown RPC service: %s", scp->name ) ;
- return( FAILED ) ;
- }
- RPCDATA( scp )->program_number = rep->r_number ;
- }
- else
- #endif /* ! NO_RPC */
- {
- struct servent *sep ;
- u_short service_port ;
-
- /*
- * Check if a protocol was specified.
- * If so, verify it is a proper protocol for the given service.
- * If no protocol was specified, find the protocol for the service
- * and its number.
- */
- if ( SPECIFIED( scp, A_PROTOCOL ) )
- {
- sep = getservbyname( scp->name, scp->protocol.name ) ;
- if ( sep == NULL )
- {
- msg( LOG_ERR, func,
- "service/protocol combination not in /etc/services: %s/%s",
- scp->name, scp->protocol.name ) ;
- return( FAILED ) ;
- }
- }
- else
- {
- struct protoent *pep ;
-
- sep = getservbyname( scp->name, (char *)0 ) ;
- if ( sep == NULL )
- {
- msg( LOG_ERR, func, "Unknown service: %s", scp->name ) ;
- return( FAILED ) ;
- }
- scp->protocol.name = make_string( 1, sep->s_proto ) ;
- if ( scp->protocol.name == NULL )
- {
- out_of_memory( func ) ;
- return( FAILED ) ;
- }
- pep = getprotobyname( sep->s_proto ) ;
- if ( pep == NULL )
- {
- msg( LOG_ERR, func,
- "Protocol %s for service %s is not in /etc/protocols",
- sep->s_proto, scp->name ) ;
- return( FAILED ) ;
- }
- scp->protocol.value = pep->p_proto ;
- }
-
- service_port = sep->s_port ; /* s_port is in network-byte-order */
-
- /*
- * If a port was specified, it must be the right one
- */
- if ( SPECIFIED( scp, A_PORT ) && scp->port != ntohs( service_port ) )
- {
- msg( LOG_ERR, func, "Service %s expects port %d, not %d",
- scp->name, ntohs( service_port ), scp->port ) ;
- return( FAILED ) ;
- }
- scp->port = ntohs( service_port ) ;
- }
- return( OK ) ;
- }
-
-
-